<template>
  <div class="audition189">
    <h3>三者共同点：</h3>
    <p>1. 都是用来改变函数this指向的</p>
    <p>2. 第一个参数都是this要指向的对象</p>
    <p>3. 都可以利用后续参数进行传参</p>
    <h3>不同点：</h3>
    <p>1. call和bind都可以有很多参数，而apply只有俩参数</p>
    <p>1. apply用数组形式传参</p>
    <p>2. call和apply会立即调用，bind会生成一个新的函数，不会立即调用</p>
    <p>手写call:</p>
    <p>核心点就在于，你想让哪个函数指向obj，你就把这个函数体放进obj里面</p>
    <v-md-preview :text="text1" />
    <p>测试：</p>
    <v-md-preview :text="text2" />
    <p>手写apply:</p>
    <v-md-preview :text="text3" />
    <p>手写bind:</p>
    <v-md-preview :text="text4" />
  </div>
</template>

<script>
const prefix = '``` js'
const suffix = '```'
export default {
  name: 'Audition189',
  data() {
    return {
      text1: `${prefix}
      Function.prototype._call = function (context, ...args) {
        // 确定上下文，如果没传或者传了null，上下文都是window
        context = context || window
        // 随便找个变量，但是这个变量一定是唯一的值，防止和原有变量冲突
        const fn = Symbol()
        // 这里的this是要改变指向的函数体
        context[fn] = this
        // 把参数传进去
        const result = context[fn](...args)
        // 删除变量
        delete context[fn]
        // 返回结果
        return result
      }
      \n${suffix}`,
      text2: `${prefix}
      var a = 1
      var obj = {
        a: 2,
        fn() {
          console.log(233)
        }
      }
      function fn() {
        console.log(this.a)
      }
      // ---------------------
      fn() // 1
      fn._call(obj) // 2
      obj.fn() // 233
      \n${suffix}`,
      text3: `${prefix}
      Function.prototype._apply = function (context, arr) {
        context = context || window
        const fn = Symbol()
        context[fn] = this
        const result = context[fn](...arr)
        delete context[fn]
        return result
      }
      \n${suffix}`,
      text4: `${prefix}
      Function.prototype._bind = function (context, ...args) {
        const fn = this
        return function () {
          fn.call(context, ...args, ...arguments)
        }
      }
      \n${suffix}`,
    }
  }
}
</script>

<style>

</style>